package cn.yunyichina.provider.guide.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.StringUtils;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

import cn.yunyichina.provider.framework.exception.CallException;
import cn.yunyichina.provider.guide.main.GuideApp;
import cn.yunyichina.provider.guide.service.impl.GuideInstanceServiceImpl;
import cn.yunyichina.provider.guide.service.impl.SpringContextHolder;
import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyShell;
import groovy.lang.Script;

public class GroovyShellYYT {
	private static final Logger logger = LoggerFactory.getLogger(GroovyShellYYT.class);

	public static void main(String args[]) {
//		GuideApp.main(null);
		//最先测试 Y520170313114210112
		//Y320170330150210112
		SpringContextHolder.getBean(GuideInstanceServiceImpl.class).startGuideInstanceReal("Y320170406095910112");//Y320170328122110119   Y3201704061703101124 Y320170330150210112
//		SpringContextHolder.getBean(GuideInstanceServiceImpl.class).runGuideInstanceByOrderNo("Y320170330150210112");//startGuideInstance("", "", "", "1", "r1", "test");
//		
//		Binding binding = new Binding();
//
//		binding.setVariable("x", 10);
//		
//		binding.setVariable("u", SpringContextHolder.getBean(GuideInstanceServiceImpl.class));
//		
//		binding.setVariable("record",cn.yunyichina.provider.framework.dubbo.service.BaseService.getBaseClient().getOrderByOrderNo("YCP201612241600130001"));
//
//		binding.setVariable("language", "Groovy");
//
//		GroovyShell shell = new GroovyShell(binding); 
////		SpringContextHolder.getBean(UserOpenidSyncServiceImpl.class)
////		Object value = shell.evaluate("println\"Welcome to $language\"; y = x * 2; z = x * 3; return x ");
////		Object value = shell.evaluate("return  cn.yunyichina.utils.convert.JsonUtils.toJsonString(cn.yunyichina.provider.framework.dubbo.service.BaseService.getBaseClient().getOrderByOrderNo(\"YCP201612241600130001\"))");
////		assert value.equals(10);
//		String script = "import cn.yunyichina.utils.convert.JsonUtils;\nreturn  \"d\"==cn.yunyichina.utils.convert.JsonUtils.toJsonString(cn.yunyichina.provider.framework.dubbo.service.BaseService.getBaseClient().getOrderByOrderNo(\"YCP201612241600130001\"))";
//		JSONObject param = new JSONObject();
//		param.put("rule_exp", script);
//		//parseSript(param);
//		param.put("templateId","templateId2");
//		param.put("templateRelationId","templateRelationId2");
//		Object value = run(param.toJSONString());
//		logger.info("" + value);
////		logger.info("" + binding.getVariable("y").equals(20));
////
////		logger.info("" + binding.getVariable("z").equals(30));
//		com.alibaba.dubbo.container.Main.main(args);

	}
	
	
	/**
	 * 解析脚本
	 * @param strScript
	 * @param param script,is_class。如果是类is_class=true,否则为false
	 */
	public static void parseSript(JSONObject param) {
		try {
			String strScript = param.getString("rule_exp");
			BufferedReader br = new BufferedReader(new StringReader(strScript));
			String line = br.readLine();
			StringBuilder sb = new StringBuilder();
			StringBuilder sbImport = new StringBuilder();
			boolean hasImport = false;
			while (line != null) {
				line = line.trim();

				if (line.length() > 0 && line.startsWith("import ")) {
					sbImport.append(line);
					sbImport.append("\n");
					hasImport = true;
				}
				else if (line.length() > 0) {
					sb.append(line);
					sb.append("\n");
				}
				line = br.readLine();
			}
			if (hasImport) {
				String className = "YYT"+System.currentTimeMillis();
				sbImport.append("import com.alibaba.fastjson.JSONArray;\n");
				sbImport.append("import com.alibaba.fastjson.JSONObject;\n");
				sbImport.append("import cn.yunyichina.provider.iface.entity.base.OrderExtVo;\n");
				sbImport.append("import org.apache.commons.lang.StringUtils;\n");
				sbImport.append("import cn.yunyichina.utils.convert.JsonUtils;\n");
				sbImport.append("import cn.yunyichina.provider.guide.entity.*;\n");
				sbImport.append("import java.util.*;\n");
				
				
				
				//import 需要用到的类,挂号，代缴费，缴费对象
				sbImport.append("public class "+className+ "{\n");
				sbImport.append("public static Boolean run(JSONObject _param) {\n");
				
				sbImport.append("OrderExtVo order = (OrderExtVo)_param.get(\"order\");\n");
//				sbImport.append("List<OrderExtVo> payedRecords = (List<OrderExtVo>)_param.get(\"payed_record\");\n");
				sbImport.append("List<OrderExtVo> payRecords = (List<OrderExtVo>)_param.get(\"pay_records\");\n");
				
				
				sbImport.append("InstanceNode node = (InstanceNode)_param.get(\"node\");\n");
				sbImport.append("InstanceRelation relation = (InstanceRelation)_param.get(\"relation\");\n");
				sbImport.append("Instance instance = (Instance)_param.get(\"instance\");\n");
				
				sbImport.append(sb.toString());
				sbImport.append("}\n");//run()
				sbImport.append("}\n");//class end
				param.put("is_class", true);
			}
			else {
				sbImport = sb;
				param.put("is_class", false);
			}
			param.put("rule_exp", sbImport.toString());
		} catch (IOException e) {
			logger.error("解析groovy脚本错误",e);
			throw new CallException("9801", "解析groovy脚本错误",e);
		}
	}
	public static boolean isCached(String key) {
		return scriptCache.containsKey(key);
	}
	
	private static Map<String, Object> scriptCache = new ConcurrentHashMap<String, Object>();
	public static Map<String, Object> getCaches() {
		return scriptCache;
	}
	/**
	 * 
	 * @param strJson
	 * @return 错误时返回null
	 */
	public static Boolean run(JSONObject param) {
		try {
			
			parseSript(param);
			logger.info(param.getString("rule_exp"));
//			String templateId = param.getString("template_id");
			String templateRelationId = null;
			if (param.containsKey("template_relation_id")) {
				templateRelationId = param.getString("template_relation_id");
			}
			if (StringUtils.isBlank(templateRelationId)) {
				templateRelationId = "common";
			}
			

			Boolean scriptObject = null;
			String script = param.getString("rule_exp");
			if (param.getBooleanValue("is_class")) {
				Class groovyClass = null;
				if ( ! isCached(templateRelationId)) {

					GroovyClassLoader loader = new GroovyClassLoader();
					groovyClass = loader.parseClass(script);
					getCaches().put(templateRelationId, groovyClass);
				}
				groovyClass = (Class) getCaches().get(templateRelationId);
				GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
				scriptObject = (Boolean) groovyObject.invokeMethod("run", param);
			}
			else {

				
				Binding binding = new Binding();
				binding.setVariable("param", param);
				
				if (param.containsKey("order")) {
					binding.setVariable("order", param.get("order"));
				}
				if (param.containsKey("pay_records")) {
					binding.setVariable("payRecords", param.get("pay_records"));
				}
				if (param.containsKey("instance")) {
					binding.setVariable("instance", param.get("instance"));
				}
				if (param.containsKey("relation")) {
					binding.setVariable("relation", param.get("relation"));
				}
				if (param.containsKey("node")) {
					binding.setVariable("node", param.get("node"));
				}
				Script shell = null;
				if (isCached(templateRelationId)) {
				    shell = (Script) getCaches().get(templateRelationId);
				} else {
				    shell = new GroovyShell().parse(script);
				}

				shell.setBinding(binding);
				
				scriptObject = (Boolean) InvokerHelper.createScript(shell.getClass(), binding).run();
				
				// clear
				binding.getVariables().clear();
				binding = null;

				// Cache
				if (!isCached(templateRelationId)) {
				    shell.setBinding(null);
				    getCaches().put(templateRelationId, shell);
				}
			}
			
			return scriptObject;
		} catch (Exception e) {
			logger.error("解析groovy错误",e);
			e.printStackTrace();
		}
		return null;
	}
}